﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using UnityEngine;

public class BinaryManager 
{

    public static string EXCEL_BINARY_PATH = Application.streamingAssetsPath + "/Binary/";

    public Dictionary<string,object> resourceMap = new Dictionary<string,object>();

    //为了其他成员能够初始化，单例实例化要最后去实例
    private static BinaryManager instance = new BinaryManager();
    public static BinaryManager Instance => instance;
    private BinaryManager() 
    {
        Initialize();
    }

    public void Initialize()
    {
        LoadExcel<TowerInfoContainer, TowerInfo>();
        LoadExcel<PlayerInfoContainer, PlayerInfo>();
        LoadExcel<TestInfoContainer, TestInfo>();
    }


    /// <summary>
    /// 将转化为二进制文件的Excel数据，转为对象并存储在字典中
    /// </summary>
    /// <typeparam name="T">数据容量类</typeparam>
    /// <typeparam name="K">数据类</typeparam>
    public void LoadExcel<T, K>()
    {
        Type containerType = typeof(T);

        Type dataType = typeof(K);

        string path = EXCEL_BINARY_PATH + dataType.Name + ".sav";
        if (!File.Exists(path))
        {
            return;
        }

        //将文件的字节全部读取
        //FileStream fs  = File.Open(path,FileMode.Open,FileAccess.Read);
        //byte[] bytes = new byte[fs.Length];
        //fs.Read(bytes, 0, bytes.Length);
        
        byte[] bytes = File.ReadAllBytes(path);

        //读取多少条数据
        int index = 0;
        int cnt = BitConverter.ToInt32(bytes, index);
        index += 4;

        //读取Key类型
        int keyStrLen = BitConverter.ToInt32(bytes, index);
        index += 4;
        string keyName = Encoding.UTF8.GetString(bytes, index, keyStrLen);
        index += keyStrLen;

        object container = Activator.CreateInstance(containerType);
        object data;

        
        for (int i = 0; i < cnt; i++)
        { 
            data = Activator.CreateInstance(dataType);
            FieldInfo[] infos = dataType.GetFields();
            foreach (FieldInfo info in infos)
            {
                if (info.FieldType == typeof(int))
                {
                    info.SetValue(data, BitConverter.ToInt32(bytes, index));
                    index += 4;
                }
                else if (info.FieldType == typeof(float))
                {
                    info.SetValue(data, BitConverter.ToSingle(bytes, index));
                    index += 4;
                }
                else if (info.FieldType == typeof(bool))
                {
                    info.SetValue(data, BitConverter.ToBoolean(bytes, index));
                    index += 1;
                }
                else if (info.FieldType == typeof(string))
                {
                    int len = BitConverter.ToInt32(bytes, index);
                    index += 4;
                    info.SetValue(data, Encoding.UTF8.GetString(bytes, index, len));
                    index += len;
                }
            }

            int key = (int)dataType.GetField(keyName).GetValue(data);

            //Container类里面的字典
            object containerVariable = containerType.GetField("container").GetValue(container);
            MethodInfo containerAddMethod = containerVariable.GetType().GetMethod("Add");
            containerAddMethod.Invoke(containerVariable, new object[] { key, data });
        }


        resourceMap.Add(typeof(T).Name, container);
        Debug.Log("GG");
    }


    public void SaveData<T>(T data, string name)
    {
        if(!Directory.Exists(Application.persistentDataPath + "/Data/"))
        {
            Directory.CreateDirectory(Application.persistentDataPath + "/Data/");
        }

        Debug.Log(Application.persistentDataPath);
        string path = Application.persistentDataPath + "/Data/" + name + ".sav";

        using (MemoryStream ms = new MemoryStream())
        {
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(ms, data);
            byte[] bytes = ms.GetBuffer();
            File.WriteAllBytes(path, bytes);
            ms.Close();
        }
    }

    public T LoadData<T>(string name) where T : class,new()
    {
        
        string path = Application.streamingAssetsPath + '/' + name + ".sav";
        if (!File.Exists(path))
        {
            path = Application.persistentDataPath + "/Data/" + name + ".sav";
            if (!File.Exists(path))
            {
                return new T();
            }
        }

        byte[] bytes = File.ReadAllBytes(path);
        T data;
        using (MemoryStream ms = new MemoryStream(bytes))
        {
            BinaryFormatter bf = new BinaryFormatter();

            data = bf.Deserialize(ms) as T;

            ms.Close();
        }

        return data;
    }
}
